#ifndef int_h
#define int_h

// this header needs
#include "bits.h"

// the below functions are functions to calculate, from bits, an integer.
// it does not assume that the system integer representation is the same
// as the integer that it is going to be read from memory. 
// that is why some math is to be done

// int_op result struct
typedef struct {
  union {
  owl_umax u;
  owl_smax s;
  } integer;
  owl_bool success;
} owl_int_op_result;

typedef enum {
  OWL_TYPE_INT_OP_RESULT = OWL_TYPE_BITARR + 1,
} owl_type_int_h;

// basic functions for integers
owl_int_op_result owl_pow_uint(owl_umax base, owl_byte exponent);
owl_int_op_result owl_pow_sint(owl_smax base, owl_byte exponent);
owl_int_op_result owl_get_max_uint(owl_umax uint1, owl_umax uint2);
owl_int_op_result owl_get_min_uint(owl_umax uint1, owl_umax uint2);

// See https://en.wikipedia.org/wiki/Signed_number_representations
owl_int_op_result owl_bits_as_uint(owl_bitarr * bits);
owl_int_op_result owl_bits_as_sign_mag_sint(owl_bitarr * bits);
owl_int_op_result owl_bits_as_1_compl_sint(owl_bitarr * bits);
owl_int_op_result owl_bits_as_2_compl_sint(owl_bitarr * bits);
owl_int_op_result owl_bits_as_off_bin_sint(owl_bitarr * bits);
owl_int_op_result owl_bits_as_bminus2_sint(owl_bitarr * bits);

// get usual unsigned/signed integers from memory
// no math calculations, assume "standard" representations
owl_int_op_result owl_get_uint(owl_bitarr * bits);
owl_int_op_result owl_get_sint(owl_bitarr * bits);

// write usual unsigned/signed integers into a bitarr
owl_bool owl_write_uint(owl_umax num, owl_bitarr * dest);
owl_bool owl_write_sint(owl_smax num, owl_bitarr * dest);

// get "standard" integers from bits
// byte aligned, 8/16/32 bits long, big/little endian
owl_int_op_result owl_get_std_uint(owl_bitarr * bits, owl_endian endian);
owl_int_op_result owl_get_std_sint(owl_bitarr * bits, owl_endian endian);

// write "standard" integers into a bitarr
// byte aligned, 8/16/32 bits long, big/little endian
owl_bool owl_write_std_uint(owl_umax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_sint(owl_smax num, owl_bitarr * dest, owl_endian endian);

// owl_get_std_uint/sint() but that increase bits -> arr -> ptr and decreases bits -> arr -> size
// by (bits -> num_bits + bits -> left_pad) / OWL_BYTE_BITS
// they treat the bits structure as a moving window (mw) over byte data
// This window is modified in each call of these functions.
owl_int_op_result owl_get_std_uint_mw(owl_bitarr * bits, owl_endian endian);
owl_int_op_result owl_get_std_sint_mw(owl_bitarr * bits, owl_endian endian);
// get standard specific integer functions with moving window
// they override bits -> num_bits
owl_int_op_result owl_get_std_uint8_mw(owl_bitarr * bits, owl_endian endian);
owl_int_op_result owl_get_std_uint16_mw(owl_bitarr * bits, owl_endian endian);
owl_int_op_result owl_get_std_uint32_mw(owl_bitarr * bits, owl_endian endian);
owl_int_op_result owl_get_std_sint8_mw(owl_bitarr * bits, owl_endian endian);
owl_int_op_result owl_get_std_sint16_mw(owl_bitarr * bits, owl_endian endian);
owl_int_op_result owl_get_std_sint32_mw(owl_bitarr * bits, owl_endian endian);

// same as the above but for writing
owl_bool owl_write_std_uint_mv(owl_umax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_sint_mv(owl_smax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_uint8_mv(owl_umax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_uint16_mv(owl_umax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_uint32_mv(owl_umax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_sint8_mv(owl_smax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_sint16_mv(owl_smax num, owl_bitarr * dest, owl_endian endian);
owl_bool owl_write_std_sint32_mv(owl_smax num, owl_bitarr * dest, owl_endian endian);

#include "int.c"

#endif // int_h
